package com.social.security;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSONUtil;
import com.social.constant.JwtConstant;
import com.social.pojo.CheckResult;
import com.social.pojo.SysUser;
import com.social.pojo.dto.UserDTO;
import com.social.service.SysUserService;
import com.social.utils.JwtUtils;
import com.social.utils.StringUtil;
import com.social.utils.UserHolder;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;

import javax.annotation.Resource;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;

import static com.social.constant.RedisConstants.LOGIN_USER_KEY;
import static com.social.constant.RedisConstants.LOGIN_USER_TTL;

/**
 * @author zhm
 */
public class JwtAuthenticationFilter extends BasicAuthenticationFilter {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private SysUserService sysUserService;

    @Autowired
    private MyUserDetailsServiceImpl myUserDetailsService;


    private static final String URL_WHITELIST[] ={
            "/login",
            "/logout",
            "/captcha",
            "/password",
            "/image/**",
            "/**/**",
            "/doc.html"
    } ;

    public JwtAuthenticationFilter(AuthenticationManager authenticationManager) {
        super(authenticationManager);
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
       // System.out.println("ssss :" + request.getParameter("token"));
       // System.out.println("isEmpty:"+StringUtil.isEmpty(null));
        System.out.println("websocket:--------------"+request.getRequestURI().contains("/websocket"));
        String token = request.getHeader("token");
        if(token == null && request.getRequestURI().contains("/websocket")){
            System.out.println("ssss");
            token = request.getAttribute("token").toString();
            //System.out.println("B1:"+token);
        }
        System.out.println("token:"+token);
        System.out.println("请求url:" + request.getRequestURI());
        // 如果token是空 或者 url在白名单里，则放行

        if(StringUtil.isEmpty(token) || new ArrayList<String>(Arrays.asList(URL_WHITELIST)).contains(request.getRequestURI())){
            chain.doFilter(request,response);
            return;
        }
        CheckResult checkResult = JwtUtils.validateJWT(token);
        if(!checkResult.isSuccess()){
            switch (checkResult.getErrCode()){
                case JwtConstant.JWT_ERRCODE_NULL:throw new JwtException("Token不存在");
                case JwtConstant.JWT_ERRCODE_FAIL:throw new JwtException("Token验证不通过");
                case JwtConstant.JWT_ERRCODE_EXPIRE:throw new JwtException("Token过期");
                default:
                    throw new IllegalStateException("出现预期外的错误：" + checkResult.getErrCode());
            }
        }

        // 从redis中获取token进行校验
        String tokenkey = LOGIN_USER_KEY + token;
//        Map<Object, Object> entries = stringRedisTemplate.opsForHash().entries(tokenkey);
        String jsonStr = stringRedisTemplate.opsForValue().get(tokenkey);
        SysUser sysUser = new SysUser();
        Claims claims = JwtUtils.parseJWT(token);
        String username = claims.getSubject();
        if (StringUtil.isEmpty(jsonStr)) {
            sysUser = sysUserService.findByUsername(username);
        } else {
            sysUser = JSONUtil.toBean(jsonStr, SysUser.class);
        }
        UserDTO userDTO = BeanUtil.copyProperties(sysUser, UserDTO.class);
        System.out.println("token解析测试：   " + sysUser);

        // 将登陆用户保存到线程池中
        UserHolder.saveUser(userDTO);
        // 刷新token过期时间
        stringRedisTemplate.expire(tokenkey, LOGIN_USER_TTL, TimeUnit.MINUTES);
        System.out.println("findID:" + sysUser.getId());
        UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =
                new UsernamePasswordAuthenticationToken(username,null,myUserDetailsService.getUserAuthority(sysUser.getId()));
        SecurityContextHolder
                .getContext()
                .setAuthentication(usernamePasswordAuthenticationToken);
        chain.doFilter(request,response);
    }
}
